package com.ruoyi.dm.component;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.enums.CollectFileStatusEnum;
import com.ruoyi.common.utils.ExecUtil;
import com.ruoyi.common.utils.biz.BizModule;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.dm.domain.BO.ResReturnBO;
import com.ruoyi.dm.domain.po.*;
import com.ruoyi.dm.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 算法策略类控制
 */
@Slf4j
@Component
public class AnalysisStrategyManager {

    @Autowired
    Executor analysisExecutor;

    @Autowired
    IAirCollectRecordService airCollectRecordService;

    @Autowired
    ISpaceEnvCollectRecordService envService;

    @Autowired
    IGroundCollectRecordService groundCollectRecordService;

    @Autowired
    private DataStrategyManager dataStrategyManager;

    @Autowired
    private IEstimateRecordService estimateRecordService;

    @Autowired
    private IReanalysisCollectRecordService reanalysisCollectRecordService;

    @Autowired
    private ISpaceTrackCollectRecordService trackCollectRecordService ;

    @Autowired
    private ApodDataStrategy apodDataStrategy;


    /**
     * 将指定的文件调用解析
     *  po 文件
     *  method 插值方法.可以为空
     */
    public void analysisAir(AirCollectRecordPO po, String method) {
        String filePath = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() + "/" + po.getFileName();
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估天基文件:{}", filePath);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    DataStrategy dataStrategy = dataStrategyManager.switchStrategy(po.getFileType(), po.getSatellite(), po.getDataType());
                    String script = dataStrategy.pythonCmd(po.getSatellite(), po.getDataType(), filePath, method,null);
                    ResReturnBO resObj = null;
                    if (StringUtils.hasLength(script)) {
                        String res = "";
                        synchronized ("analysisAir") {
                            res = RuntimeUtil.execForStr(script);
                        }
                        log.info("解析结果:{}", res);
                        resObj = JSON.parseObject(res, ResReturnBO.class);
                    }else {
                        resObj = dataStrategy.analysis(filePath);
                    }

                    if (1 == resObj.getCode()) {
                        //更新文件状态 结果文件比较多，先置空
                        String outFile = resObj.getOutFile();
                        resObj.setOutFile("");
                        String res = JSON.toJSONString(resObj);

                        //密度数据入库
                        dataStrategy.save(po.getSatellite(),outFile);

                        LambdaUpdateWrapper<AirCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(AirCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_SUCC.getCode());
                        updateWrapper.set(AirCollectRecordPO::getResFile, res);
                        updateWrapper.set(AirCollectRecordPO::getFileDesc, "");
                        updateWrapper.eq(AirCollectRecordPO::getId, po.getId());
                        airCollectRecordService.update(updateWrapper);
                    } else {
                        //异常
                        log.error("解析异常：{}", filePath);
                        LambdaUpdateWrapper<AirCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(AirCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                        updateWrapper.set(AirCollectRecordPO::getFileDesc, "解析异常：" + resObj==null?"":resObj.getMsg());
                        updateWrapper.eq(AirCollectRecordPO::getId, po.getId());
                        airCollectRecordService.update(updateWrapper);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                    LambdaUpdateWrapper<AirCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.set(AirCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                    updateWrapper.set(AirCollectRecordPO::getFileDesc, "执行异常：" + e.getMessage());
                    updateWrapper.eq(AirCollectRecordPO::getId, po.getId());
                    airCollectRecordService.update(updateWrapper);
                }
            }
        });
    }

    /**
     * 将指定的文件调用解析
     *  po 文件
     *  method 插值方法.可以为空
     */
    public void analysisEnv(SpaceEnvCollectRecordPO po, String method) {
        String fileOrgion = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() + "/" + po.getFileName();
        //因为脚本只识别大写的,转为大写
        String name = po.getFileName().split("\\.")[0].toUpperCase() + ".txt";
        String filePath = PathUtil.tmpModuleDir(BizModule.COLLECT) + po.getFilePath() + "/" + name;
        FileUtil.copy(fileOrgion,filePath,false);
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估空间环境观测文件:{}", filePath);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    DataStrategy dataStrategy = dataStrategyManager.switchStrategy(po.getFileType(), null, null);
                    ResReturnBO resObj = null;
                    String res = "";
                    if ("E107".equals(po.getDataType())) {
                        //e107暂时没有 解析脚本
                        resObj = new ResReturnBO();
                        resObj.setCode(1);
                        resObj.setLogFile(filePath);
                        int totalLines = FileUtil.getTotalLines(new File(filePath));
                        //首行是表头
                        resObj.setTotal(totalLines-1);
                        resObj.setError(0);
                        resObj.setOutFile(filePath);
                        res = JSONUtil.toJsonStr(resObj);
                    }else {
                        String script = dataStrategy.pythonCmd(null, null, filePath, method,null);
                        res = RuntimeUtil.execForStr(script);
                        log.info("解析结果:{}", res);
                        resObj = JSON.parseObject(res, ResReturnBO.class);
                    }

                    if (1 == resObj.getCode()) {
                        //结果保存
                        envService.afterAnalysis(po,resObj.getOutFile());

                        //更新文件状态
                        LambdaUpdateWrapper<SpaceEnvCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(SpaceEnvCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_SUCC.getCode());
                        updateWrapper.set(SpaceEnvCollectRecordPO::getResFile, res);
                        updateWrapper.set(SpaceEnvCollectRecordPO::getFileDesc, "");
                        updateWrapper.eq(SpaceEnvCollectRecordPO::getId, po.getId());
                        envService.update(updateWrapper);
                    } else {
                        //异常
                        log.error("解析异常：{}", filePath, res);
                        LambdaUpdateWrapper<SpaceEnvCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(SpaceEnvCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                        updateWrapper.set(SpaceEnvCollectRecordPO::getFileDesc, "解析异常：" + res);
                        updateWrapper.eq(SpaceEnvCollectRecordPO::getId, po.getId());
                        envService.update(updateWrapper);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                    LambdaUpdateWrapper<SpaceEnvCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.set(SpaceEnvCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                    updateWrapper.set(SpaceEnvCollectRecordPO::getFileDesc, "执行异常：" + e.getMessage());
                    updateWrapper.eq(SpaceEnvCollectRecordPO::getId, po.getId());
                    envService.update(updateWrapper);
                }
            }
        });
    }

    /**
     * 将 整年数据 按日拆分
     * @param filePath
     */
    private  List<EstimateRecordPO> splitYearFile(String filePath,String fileType,String station) {
        List<String> lines = FileUtil.readLines(filePath, Charset.forName("utf-8"));
        List<String> list = new ArrayList<>();
        List<EstimateRecordPO> resList = new ArrayList<>();
        double errorRate = 0;
        int errorNum = 0;
        Date yyyyMMdd = null;
        String yyyyMMddStr = null;
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            list.add(line);
            if (line.startsWith("占比：")) {
                String[] split = line.split("：|%");
                errorRate= Double.valueOf(split[1]);
                int toal = (int)(errorNum*100/errorRate);
                String replace = filePath.replace(".txt", "_" + yyyyMMddStr + ".txt");
                FileUtil.writeLines(list, replace,"utf-8");
                list = new ArrayList<>();
                EstimateRecordPO estimateRecordPO = new EstimateRecordPO();
                estimateRecordPO.setOutFile(filePath);
                estimateRecordPO.setFilePath(replace);
                estimateRecordPO.setTotal(toal);
                estimateRecordPO.setErrorNum(errorNum);
                estimateRecordPO.setDataTime(yyyyMMdd);
                estimateRecordPO.setStation(station);
                estimateRecordPO.setFileType(fileType);
                resList.add(estimateRecordPO);
            }else if (line.startsWith("剔除数据总数：")) {
                String[] split = line.split("：");
                errorNum= Integer.valueOf(split[1]);
            }if (line.startsWith("时间：")) {
                String[] split = line.split("：");
                yyyyMMddStr = split[1].substring(0,8);
                yyyyMMdd = DateUtil.parse(split[1].substring(0,8), "yyyyMMdd");
            }
        }
        return resList;
    }

    /**
     * 将指定的文件调用解析
     *  po 文件
     *  year 解析的年份
     */
    public void analysisGroundRadar(GroundCollectRecordPO po, Integer year, String method) {
        //雷达 只传入文件夹
        String filePath = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() ;
        String path = new File(filePath).getParentFile().getAbsolutePath();
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估地基文件:{}", path);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    String script = dataStrategyManager.switchStrategy(po.getFileType(), po.getStation(), null).pythonCmd(po.getStation(), null, path, method,year);
                    String res = RuntimeUtil.execForStr(script);
                    log.info("解析结果:{}", res);
                    ResReturnBO resObj = JSON.parseObject(res, ResReturnBO.class);
                    if (1 == resObj.getCode()) {
                        //保存评估结果 /dgdq/output/collect/result/wind/MH/MH_2021.nc
                        //雷达是逐年的,   现在按日拆分  时间：20200101
                        List<EstimateRecordPO> estimateRecordPOS = splitYearFile(resObj.getLogFile(), po.getFileType(), po.getStation());
                        LambdaUpdateWrapper<EstimateRecordPO> updateWapper = new LambdaUpdateWrapper<>();
                        updateWapper.eq(EstimateRecordPO::getFileType,po.getFileType());
                        updateWapper.eq(EstimateRecordPO::getStation,po.getStation());
                        DateTime time = DateUtil.parse(year + "0101", "yyyyMMdd");
                        DateTime start = DateUtil.beginOfYear(time);
                        DateTime end = DateUtil.endOfYear(time);
                        updateWapper.between(EstimateRecordPO::getDataTime,start,end);
                        estimateRecordService.remove(updateWapper);
                        estimateRecordService.saveBatch(estimateRecordPOS);
                    } else {
                        //异常
                        log.error("解析异常：{}", filePath, res);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                }
            }
        });
    }

    /**
     * 将指定的文件调用解析 无线电探空
     *  po 文件
     *  year 解析的年份
     */
    public void analysisGroundRadio(GroundCollectRecordPO po, String year, String method) {
        //
        String filePath = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() +"/"+po.getFileName();
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估无线电探空文件:{}", filePath);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    String script = dataStrategyManager.switchStrategy(po.getFileType(), null, null).pythonCmd(null, null, filePath, method,Integer.valueOf(year));
                    String res = RuntimeUtil.execForStr(script);
                    log.info("解析结果:{}", res);
                    ResReturnBO resObj = JSON.parseObject(res, ResReturnBO.class);
                    if (1 == resObj.getCode()) {
                        //保存评估结果
                        EstimateRecordPO estimateRecordPO = new EstimateRecordPO();
                        estimateRecordPO.setErrorNum(resObj.getError());
                        estimateRecordPO.setTotal(resObj.getTotal());
                        estimateRecordPO.setFileType(po.getFileType());
                        Date yyyyMMddHH = DateUtil.parse(year, "yyyyMMddHH");
                        estimateRecordPO.setDataTime(yyyyMMddHH);
                        estimateRecordPO.setOutFile(resObj.getOutFile());
                        estimateRecordPO.setFilePath(resObj.getLogFile());
                        estimateRecordPO.setStation(po.getStation());

                        LambdaUpdateWrapper<EstimateRecordPO> updateWapper = new LambdaUpdateWrapper<>();
                        updateWapper.eq(EstimateRecordPO::getFileType,po.getFileType());
                        updateWapper.eq(EstimateRecordPO::getStation,po.getStation());
                        updateWapper.eq(EstimateRecordPO::getDataTime,yyyyMMddHH);
                        estimateRecordService.saveOrUpdate(estimateRecordPO);

                    } else {
                        //异常
                        log.error("解析异常：{}", filePath, res);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                }
            }
        });
    }

    /**
     * 将指定的文件调用解析
     *  再分析文件
     *  method 插值方法.可以为空
     */
    public void analysisReAnalysis(ReanalysisCollectRecordPO po, String method, Double lon, Double lat, Double hight) {
        String filePath = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() + "/" + po.getFileName();
        //设置默认值
        final String methodInner = StringUtils.hasLength(method)?method:"linear";
        final Double lonInner = null == lon?2.5:lon;
        final Double latInner = null == lat?2.5:lat;
        final Double hightInner = null == hight?2.5:hight;
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估再分析文件:{}", filePath);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    //设置 网格间距
                    String gridStep = JSON.toJSONString(ListUtil.of(lonInner,latInner,hightInner));
                    String script = dataStrategyManager.switchStrategy(po.getFileType(),null,null)
                            .pythonCmd(null, gridStep, filePath, methodInner,null);
                    String res = RuntimeUtil.execForStr(script);
                    log.info("解析结果:{}", res);
                    String[] split = res.split("\n");
                    ResReturnBO resObj = JSON.parseObject(split[split.length-1], ResReturnBO.class);
                    if (1 == resObj.getCode()) {
                        //更新文件状态 结果文件比较多，先置空
                        resObj.setOutFile("");
                        res = JSON.toJSONString(resObj);
                        LambdaUpdateWrapper<ReanalysisCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(ReanalysisCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_SUCC.getCode());
                        updateWrapper.set(ReanalysisCollectRecordPO::getResFile, res);
                        updateWrapper.set(ReanalysisCollectRecordPO::getFileDesc, "");
                        updateWrapper.eq(ReanalysisCollectRecordPO::getId, po.getId());
                        reanalysisCollectRecordService.update(updateWrapper);
                    } else {
                        //异常
                        log.error("解析异常：{}", filePath, res);
                        LambdaUpdateWrapper<ReanalysisCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(ReanalysisCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                        updateWrapper.set(ReanalysisCollectRecordPO::getFileDesc, "解析异常：" + res);
                        updateWrapper.eq(ReanalysisCollectRecordPO::getId, po.getId());
                        reanalysisCollectRecordService.update(updateWrapper);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                    LambdaUpdateWrapper<ReanalysisCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.set(ReanalysisCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                    updateWrapper.set(ReanalysisCollectRecordPO::getFileDesc, "执行异常：" + e.getMessage());
                    updateWrapper.eq(ReanalysisCollectRecordPO::getId, po.getId());
                    reanalysisCollectRecordService.update(updateWrapper);
                }
            }
        });
    }

    /**
     * 空间目标轨道解析
     */
    public void analysisTrack(SpaceTrackCollectRecordPO po) {
        String filePath = PathUtil.outputModuleDir(BizModule.COLLECT) + po.getFilePath() + "/" + po.getFileName();
        analysisExecutor.execute(new Runnable() {
            @Override
            public void run() {
                log.info("开始评估目标轨道文件:{}", filePath);
                try {
                    //调用评估算法  配置文件输入,产品输出参数
                    ResReturnBO resObj = null;
                    DataStrategy dataStrategy = dataStrategyManager.switchStrategy(po.getFileType(), po.getSatellite(), po.getDataType());
                    String script = dataStrategy.pythonCmd(po.getSatellite(),null, filePath, null,null);
                    if (StringUtils.hasLength(script)) {
                        String command = "cd /dgdq/code/dgdq-algorithm/collect/testTleDataAlgo/bin && "+script;

                        List<String> commandList = Stream.of("bash", "-c", command).collect(Collectors.toList());
                        String res = "";
                        synchronized ("testTleDataAlgo") {
                            try {
                                Thread.sleep(300);
                            }catch (Exception e) {
                                //
                            }
                            res = ExecUtil.execTLENoSendSse(commandList,null);
                        }
                        log.info("解析结果:{}", JSON.toJSONString(res));
                        String[] lines = res.split("[\r\n]+");
                        //tle 未输出json格式信息
                        resObj = new ResReturnBO();
                        for (String line : lines) {
                            if (line.startsWith("TLE size is")) {
                                resObj.setTotal(Integer.valueOf(line.split(":")[1].trim()));
                            }else if (line.startsWith("Error TLE size")) {
                                resObj.setError(Integer.valueOf(line.split(":")[1].trim()));
                            }else if (line.startsWith("True TLE Path")) {
                                String outPath = line.split(":")[1].trim();
                                resObj.setOutFile(outPath);
                            }else if (line.startsWith("Error TLE Path")) {

                            }
                        }
                        //将输出写入 日志
                        //文件在 输出路径 的 /yyyyMMdd 下
                        String outPath = PathUtil.outputModuleDir(BizModule.COLLECT) + PathUtil.moduleDirs().getCollect().get("result") + "/" + po.getFileType() + "/" ;
                        String log = outPath+ UUID.fastUUID()+".log";
                        File file = FileUtil.writeString(res, log, "utf-8");
                        resObj.setLogFile(file.getAbsolutePath());
                        resObj.setCode(1);
                    }else {
                        //没有,说明无需调用脚本
                        resObj = new ResReturnBO();
                        resObj.setOutFile(filePath);
                        resObj.setCode(1);
                    }
                    if (1 == resObj.getCode()) {
                        //更新文件状态 结果文件比较多，先置空
                        dataStrategyManager.switchStrategy(po.getFileType(), po.getSatellite(), po.getDataType()).save(po.getSatellite(),resObj.getOutFile());
                        resObj.setOutFile("");
                        String res = JSON.toJSONString(resObj);
                        LambdaUpdateWrapper<SpaceTrackCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(SpaceTrackCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_SUCC.getCode());
                        updateWrapper.set(SpaceTrackCollectRecordPO::getResFile, res);
                        updateWrapper.set(SpaceTrackCollectRecordPO::getFileDesc, "");
                        updateWrapper.eq(SpaceTrackCollectRecordPO::getId, po.getId());
                        trackCollectRecordService.update(updateWrapper);
                    } else {
                        //异常
                        log.error("解析异常：{}", filePath);
                        LambdaUpdateWrapper<SpaceTrackCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(SpaceTrackCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                        updateWrapper.set(SpaceTrackCollectRecordPO::getFileDesc, "解析异常");
                        updateWrapper.eq(SpaceTrackCollectRecordPO::getId, po.getId());
                        trackCollectRecordService.update(updateWrapper);
                    }
                }catch (Exception e) {
                    log.error("执行异常：{}", filePath, e);
                    LambdaUpdateWrapper<SpaceTrackCollectRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
                    updateWrapper.set(SpaceTrackCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_ERROR.getCode());
                    updateWrapper.set(SpaceTrackCollectRecordPO::getFileDesc, "执行异常：" + e.getMessage());
                    updateWrapper.eq(SpaceTrackCollectRecordPO::getId, po.getId());
                    trackCollectRecordService.update(updateWrapper);
                }
            }
        });
    }
}
